﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Reflection;




namespace com.eFORCE.CommonUtilsForSearch
{
    public class ReflectionUtils
    {
        /// <summary>
        /// Takes the DataSource of the GridView as a parameter and converts it to a Data Table
        /// </summary>
        /// <param name="objDataSource"></param>
        /// <returns>DataTable</returns>
        public static DataTable ConvertToDataTable(object objDataSource)
        {
            DataTable dtResult = new DataTable("DataTable");
            if (objDataSource.GetType().Equals(typeof(DataTable)))
            {
                return (DataTable)objDataSource;
            }
            else if (objDataSource.GetType().Equals(typeof(DataSet)))
            {
                DataSet dsSource = (DataSet)objDataSource;
                dtResult = dsSource.Tables[0];
            }
            else if (objDataSource.GetType().Equals(typeof(DataView)))
            {
                DataView dvSource = (DataView)objDataSource;
                dtResult = (DataTable)dvSource.ToTable();
            }
            else if (objDataSource is IEnumerable)
            {
                IEnumerable data = (IEnumerable)objDataSource;
                Type innerType = data.GetType().GetGenericArguments()[0];
                bool isCustomObject = false;
                if (IsTypeBasic(innerType))
                {
                    isCustomObject = false;
                }
                else if (innerType.IsClass)
                {
                    isCustomObject = true;
                }
                if (isCustomObject)
                {
                    List<PropertyInfo> listProperties = GetPropertyInfo(innerType);
                    foreach (PropertyInfo pi in listProperties)
                    {
                        dtResult.Columns.Add(GetDataColumnForProperty(pi));
                    }
                    IEnumerator enumerator = data.GetEnumerator();
                    while (enumerator.MoveNext())
                    {
                        object enumData = enumerator.Current;
                        DataRow drNew = dtResult.NewRow();
                        foreach (PropertyInfo pi in listProperties)
                        {
                            object value = GetPropertyValue(enumData, pi);
                            if (value != null)
                                drNew[pi.Name] = value;
                        }
                        dtResult.Rows.Add(drNew);
                    }
                }
                else
                {
                    DataColumn dcNew = new DataColumn("Item", innerType);
                    dtResult.Columns.Add(dcNew);
                    IEnumerator enumerator = data.GetEnumerator();
                    while (enumerator.MoveNext())
                    {
                        object enumData = enumerator.Current;
                        DataRow drNew = dtResult.NewRow();
                        drNew[dcNew] = enumData;
                        dtResult.Rows.Add(drNew);
                    }
                }
            }
            return dtResult;
        }

        /// <summary>
        /// Checks if the type of the Data Source of the GridView is Basic/primitive type or not
        /// </summary>
        /// <param name="type"></param>
        /// <returns>true/false</returns>
        private static bool IsTypeBasic(Type type)
        {
            bool isValid = false;
            List<string> listBasicTypes = new List<string>
                                              {
                                                  "System.SByte",
                                                  "System.Byte",
                                                  "System.Int16",
                                                  "System.UInt16",
                                                  "System.Int32",
                                                  "System.UInt32",
                                                  "System.Int64",
                                                  "System.UInt64",
                                                  "System.Single",
                                                  "System.Double",
                                                  "System.Decimal",
                                                  "System.Boolean",
                                                  "System.Char",
                                                  "System.String",
                                                  "System.DateTime"
                                              };
            if (listBasicTypes.Contains(type.FullName))
                isValid = true;
            return isValid;
        }

        /// <summary>
        /// Gets the value of the property of the DataSource
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="pi"></param>
        /// <returns>object</returns>
        public static object GetPropertyValue(object entity, PropertyInfo pi)
        {
            return pi.GetValue(entity, null);
        }

        /// <summary>
        /// Sets the value of the property of the DataSource
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="pi"></param>
        /// <param name="value"></param>
        /// <returns>object</returns>
        public static object SetPropertyValue(object entity, PropertyInfo pi, object value)
        {
            pi.SetValue(entity, Convert.ChangeType(value, pi.PropertyType), null);
            return entity;
        }

        /// <summary>
        /// Gets the property for the Data Column  
        /// </summary>
        /// <param name="pi"></param>
        /// <returns>DataColumn</returns>
        private static DataColumn GetDataColumnForProperty(PropertyInfo pi)
        {
            DataColumn dc = new DataColumn();
            dc.ColumnName = pi.Name;
            Type columnType;
            Type piType = pi.PropertyType;
            if (piType.IsGenericType && piType.GetGenericTypeDefinition() == typeof(Nullable<>))
            {
                columnType = piType.GetGenericArguments()[0];
            }
            else
            {
                columnType = pi.PropertyType;
            }
            dc.DataType = columnType;
            return dc;
        }

        /// <summary>
        /// Takes the Type as parameter and returns list of properttinfo for the Type
        /// </summary>
        /// <param name="listType"></param>
        /// <returns>List<PropertyInfo></returns>
        private static List<PropertyInfo> GetPropertyInfo(Type listType)
        {
            List<PropertyInfo> list = new List<PropertyInfo>();
            Object obj = Activator.CreateInstance(listType);
            List<PropertyInfo> listPropertyInfo = listType.GetProperties().Where(pi => pi.CanRead || pi.CanWrite).ToList();
            return listPropertyInfo;
        }
    }
}
